In [1]:
import os
import sys
import importlib

import scipy.ndimage as snd

os.chdir("../..")
directory_path = os.path.abspath(os.path.join("src"))
if directory_path not in sys.path:
    sys.path.append(directory_path)

import EyeTraumaAnalysis
In [2]:
print(directory_path)
C:\Users\ethan\PycharmProjects\EyeTraumaAnalysis\src
In [3]:
importlib.reload(EyeTraumaAnalysis);
In [4]:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import matplotlib as mpl
import cv2
In [5]:
# images = ["10030.jpg", "10031.jpg", "10032.jpg", "10033.jpg", "10034.jpg", "10035.jpg", "10036.jpg", "10037.jpg", "10038.jpg", "10039.jpg", "10040.jpg", "10041.jpg", "10042.jpg"]
In [5]:
images = os.listdir('./data/01_raw/Ergonautus/Full Dataset/')
In [6]:
def get_spatial_metrics(mask):
    # scipy can perform the mean (center of mass), but not the standard deviation
    # spatial_means = snd.center_of_mass(mask)
    x = np.linspace(0, 1, mask.shape[1])
    y = np.linspace(0, 1, mask.shape[0])
    xgrid, ygrid = np.meshgrid(x, y)
    grids = {"x": xgrid, "y":ygrid}
    to_return = {"x":{}, "y":{}}
    for ind, grid in grids.items():
        to_return[ind]["mean"] = np.mean(grids[ind], where=mask.astype(bool))
        to_return[ind]["sd"] = np.std(grids[ind], where=mask.astype(bool))
    return to_return
In [7]:
### Create K means clusters and masks
image = EyeTraumaAnalysis.Image("data/01_raw/11000.jpg")
img_bgr = image.img
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
Z_hsv = img_hsv.reshape((-1,3))
# convert to np.float32
Z_hsv = np.float32(Z_hsv)
# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 10
ret,label,centers=cv2.kmeans(Z_hsv,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
# Now convert back into uint8, and make original image
centers = np.uint8(centers)
res_hsv = centers[label.flatten()]
res_hsv2 = res_hsv.reshape(img_hsv.shape)
res_bgr = cv2.cvtColor(res_hsv2, cv2.COLOR_HSV2BGR)
# res2 = cv2.cvtColor(res2, cv2.COLOR_RGB2GRAY)


# sort centers by HSV "value" - aka sort by grayscale
centers_sorted = centers[centers[:, 2].argsort()]
kmeans_thresholds = []
for ind in range(K):
    kmeans_thresholds.append(cv2.inRange(res_hsv2,centers_sorted[ind],centers_sorted[ind]))
summed_image = np.zeros(kmeans_thresholds[0].shape)
for ind in range(K):
    summed_image += int(ind/K*255) * kmeans_thresholds[ind]
centers_indices = centers_sorted.argsort(axis=0)   # sorts each column separately
In [8]:
### Clustered View ### <-- for individual image use
fig, axs = plt.subplots(2, 2, figsize=(12,6))
im0=axs.flat[0].imshow(img_bgr)
im1=axs.flat[1].imshow(res_bgr)
im2=axs.flat[2].imshow(summed_image, cmap="gray")
im3=axs.flat[3].imshow(summed_image, cmap="terrain")
plt.colorbar(im3,ax=axs.flat[3], shrink=0.8)
Out[8]:
<matplotlib.colorbar.Colorbar at 0x1f5e26dee48>
In [9]:
get_spatial_metrics(kmeans_thresholds[0])
Out[9]:
{'x': {'mean': 0.5017151478843548, 'sd': 0.0847618072972454},
 'y': {'mean': 0.48749778466138083, 'sd': 0.08289419964726637}}
In [82]:
 
Out[82]:
array([4, 7, 0])
In [10]:
### Per Cluster Masking ### <-- for individual image use

row_ct = int(np.sqrt(K))
col_ct = int(np.ceil(K/row_ct))
fig, axs = plt.subplots(row_ct, col_ct, figsize=(12,6), sharex=True, sharey=True)
for ind in range(row_ct*col_ct):
    if ind < K:
        #target1 = cv2.bitwise_and(image.img,image.img, mask=~kmeans_thresholds[ind])
        target1 = image.img.copy()
        target1[kmeans_thresholds[ind].astype(bool)] = [127,255,127,255]
        axs.flat[ind].imshow(target1)
        spatial_metrics = get_spatial_metrics(kmeans_thresholds[ind])
        hsv_rank = centers_indices[ind]
        hsv_center = centers_sorted[ind]
        # Draw left title
        axs.flat[ind].set_title(
            "HSV \n"+
            f"#{hsv_rank[0]+1}, #{hsv_rank[1]+1}, #{hsv_rank[2]+1}" + "\n" +
            f"({hsv_center[0]}, {hsv_center[1]}, {hsv_center[2]})",
            fontsize=8, loc="left"
        )
        # Draw right title
        axs.flat[ind].set_title(
            f"Location:" + "\n"+
            f"({spatial_metrics['x']['mean']*100:.1f}, {spatial_metrics['y']['mean']:.1%})" + "\n" +
            f"({spatial_metrics['x']['sd']*100:.1f}, {spatial_metrics['y']['sd']:.1%})",
            fontsize=8, loc="right", fontfamily="monospace",
        )
        # axs.flat[ind].set_title(
        #     f"HSV center: [{centers_sorted[ind,0]},{centers_sorted[ind,1]},{centers_sorted[ind,2]}]" )
        #axs.flat[ind].imshow(kmeans_thresholds[ind], cmap="gray")
    else:
        # remove axes for empty cells
        axs.flat[ind].axis("off")
In [101]:
target1[kmeans_thresholds[ind].astype(bool)]
Out[101]:
array([[ 12,  12,  14, 255],
       [ 11,  11,  13, 255],
       [ 11,  11,  13, 255],
       [ 11,  11,  11, 255],
       [ 10,  10,  10, 255],
       [ 10,  10,  10, 255],
       [ 12,  12,  14, 255],
       [ 13,  13,  15, 255],
       [ 12,  12,  14, 255],
       [ 12,  12,  14, 255],
       [ 13,  13,  15, 255],
       [ 11,  11,  13, 255],
       [ 13,  13,  15, 255],
       [ 12,  13,  17, 255],
       [ 10,  11,  13, 255],
       [ 12,  12,  14, 255],
       [ 13,  13,  15, 255],
       [ 12,  12,  14, 255],
       [ 12,  12,  14, 255],
       [ 12,  12,  14, 255],
       [ 10,  10,  12, 255],
       [ 12,  13,  17, 255],
       [ 13,  14,  19, 255],
       [ 11,  12,  16, 255],
       [ 11,  12,  16, 255],
       [ 11,  12,  16, 255],
       [ 11,  11,  13, 255],
       [ 11,  11,  13, 255],
       [ 11,  11,  13, 255],
       [  9,   9,  11, 255],
       [ 46,  46,  56, 255],
       [  9,  10,  15, 255],
       [ 10,  11,  16, 255],
       [  9,  10,  15, 255],
       [ 10,  11,  15, 255],
       [ 11,  12,  16, 255],
       [ 11,  11,  13, 255],
       [ 11,  11,  13, 255],
       [ 12,  12,  14, 255],
       [ 11,  11,  13, 255],
       [ 40,  40,  50, 255],
       [  8,   8,  16, 255],
       [  9,  10,  15, 255],
       [ 38,  38,  48, 255],
       [ 12,  12,  20, 255],
       [ 12,  13,  18, 255],
       [ 39,  39,  49, 255],
       [ 38,  38,  48, 255],
       [ 32,  32,  42, 255],
       [ 26,  26,  36, 255],
       [ 48,  48,  58, 255],
       [ 22,  22,  32, 255],
       [ 41,  41,  51, 255],
       [ 15,  16,  21, 255],
       [ 14,  15,  20, 255],
       [ 14,  15,  20, 255],
       [ 16,  16,  18, 255],
       [ 15,  15,  17, 255],
       [ 12,  13,  17, 255],
       [ 10,  11,  15, 255],
       [ 12,  13,  17, 255],
       [ 13,  13,  21, 255],
       [ 15,  15,  23, 255],
       [ 22,  22,  32, 255],
       [ 39,  39,  49, 255],
       [ 19,  20,  25, 255],
       [ 18,  19,  24, 255],
       [ 14,  15,  20, 255],
       [ 14,  15,  20, 255],
       [ 15,  15,  17, 255],
       [ 15,  15,  17, 255],
       [ 14,  15,  19, 255],
       [ 11,  12,  16, 255],
       [  8,  12,  15, 255],
       [ 11,  15,  18, 255],
       [ 11,  12,  17, 255],
       [ 13,  13,  21, 255],
       [ 15,  15,  23, 255],
       [ 22,  22,  30, 255],
       [ 38,  38,  48, 255],
       [ 16,  16,  24, 255],
       [ 15,  18,  25, 255],
       [ 16,  16,  24, 255],
       [ 14,  15,  20, 255],
       [ 15,  15,  17, 255],
       [ 12,  13,  15, 255],
       [  9,  10,  12, 255],
       [  9,  13,  16, 255],
       [ 13,  17,  20, 255],
       [ 15,  16,  21, 255],
       [ 12,  13,  18, 255],
       [ 11,  12,  17, 255],
       [ 11,  12,  17, 255],
       [ 16,  17,  22, 255],
       [ 16,  16,  24, 255],
       [ 16,  19,  26, 255],
       [ 18,  18,  26, 255],
       [ 16,  16,  24, 255],
       [ 15,  15,  17, 255],
       [ 14,  14,  16, 255],
       [ 11,  12,  14, 255],
       [ 10,  14,  17, 255],
       [ 13,  17,  20, 255],
       [ 16,  17,  22, 255],
       [ 13,  14,  19, 255],
       [ 12,  13,  18, 255],
       [ 11,  12,  17, 255],
       [ 17,  18,  23, 255],
       [ 16,  16,  24, 255],
       [ 17,  20,  27, 255],
       [ 19,  19,  27, 255],
       [ 17,  17,  25, 255],
       [ 12,  13,  17, 255],
       [ 10,  14,  17, 255],
       [ 12,  16,  19, 255],
       [ 16,  17,  22, 255],
       [ 13,  14,  19, 255],
       [ 12,  13,  18, 255],
       [ 10,  11,  16, 255],
       [ 16,  17,  22, 255],
       [ 17,  20,  27, 255],
       [ 20,  20,  28, 255],
       [ 18,  18,  26, 255],
       [ 13,  14,  18, 255],
       [ 13,  14,  18, 255],
       [ 11,  15,  18, 255],
       [ 14,  15,  20, 255],
       [ 12,  13,  18, 255],
       [ 12,  13,  18, 255],
       [ 10,  11,  16, 255],
       [ 16,  17,  22, 255],
       [ 16,  19,  24, 255],
       [ 17,  20,  27, 255],
       [ 19,  19,  27, 255],
       [ 14,  15,  19, 255],
       [ 13,  14,  18, 255],
       [ 13,  14,  18, 255],
       [ 13,  14,  19, 255],
       [ 12,  13,  18, 255],
       [ 12,  13,  18, 255],
       [ 10,  11,  16, 255],
       [ 17,  17,  19, 255],
       [ 17,  18,  22, 255],
       [ 16,  19,  24, 255],
       [ 17,  20,  27, 255],
       [ 19,  19,  27, 255],
       [ 13,  14,  18, 255],
       [ 12,  13,  17, 255],
       [ 13,  14,  19, 255],
       [ 12,  13,  18, 255],
       [ 13,  14,  19, 255],
       [ 11,  12,  17, 255],
       [ 18,  19,  24, 255],
       [ 18,  18,  26, 255],
       [ 20,  20,  28, 255],
       [ 14,  15,  19, 255],
       [ 13,  14,  18, 255],
       [ 14,  15,  20, 255],
       [ 12,  13,  18, 255],
       [ 14,  15,  20, 255],
       [ 11,  12,  17, 255],
       [ 21,  21,  23, 255],
       [ 18,  19,  23, 255],
       [ 19,  20,  25, 255],
       [ 21,  21,  29, 255],
       [ 15,  16,  20, 255],
       [ 13,  14,  18, 255],
       [ 13,  14,  19, 255],
       [ 12,  13,  18, 255],
       [ 14,  15,  20, 255],
       [ 12,  13,  18, 255],
       [ 19,  20,  25, 255],
       [ 20,  21,  26, 255],
       [ 17,  18,  23, 255],
       [ 15,  16,  21, 255],
       [ 13,  14,  19, 255],
       [ 13,  14,  19, 255],
       [ 14,  15,  20, 255],
       [ 14,  15,  20, 255],
       [ 20,  21,  26, 255],
       [ 17,  18,  23, 255],
       [ 16,  17,  22, 255],
       [ 14,  15,  20, 255],
       [ 14,  15,  20, 255],
       [ 14,  15,  20, 255],
       [ 15,  16,  21, 255],
       [ 18,  19,  24, 255],
       [ 17,  18,  23, 255],
       [ 17,  18,  23, 255],
       [ 17,  18,  23, 255],
       [ 17,  18,  23, 255],
       [ 18,  19,  24, 255],
       [ 16,  17,  22, 255],
       [ 15,  16,  21, 255],
       [ 16,  17,  22, 255],
       [ 17,  18,  23, 255],
       [ 16,  17,  22, 255],
       [ 12,  15,  20, 255],
       [ 13,  16,  21, 255],
       [ 17,  17,  25, 255],
       [ 16,  16,  24, 255],
       [ 13,  16,  23, 255],
       [ 14,  17,  24, 255],
       [ 16,  16,  24, 255],
       [ 15,  15,  23, 255],
       [ 17,  17,  25, 255],
       [ 17,  17,  25, 255],
       [ 14,  14,  22, 255],
       [ 14,  14,  22, 255],
       [ 17,  17,  25, 255],
       [ 16,  16,  24, 255]], dtype=uint8)
In [102]:
image.img.shape
Out[102]:
(240, 416, 4)
In [23]:
kmeans_thresholds[0].dtype
Out[23]:
dtype('uint8')
In [27]:
xgrid
Out[27]:
array([0.        , 0.        , 0.        , ..., 0.61445783, 0.61445783,
       0.61445783])
In [22]:
type(xgrid)
Out[22]:
numpy.ndarray
In [ ]:
### Running Code on Several Images ###

K = 10
# save_directory = "C:\\Users\\ethan\\PycharmProjects\\EyeTraumaAnalysis\\data\\kmeans_clustering_applied" # data/kmeans_clustering_applied; hard coded for PC
# NOTE: While this isn't a preferable implementation, the previous code, which was flexible per system, ran into PermissionError [Errno 13]

for image_sample in images:
    # image = EyeTraumaAnalysis.Image(f"data/01_raw/{image_sample}")
    image = EyeTraumaAnalysis.Image(f"data/01_raw/Ergonautus/Full Dataset/{image_sample}")

    ## Clustered View
    img_bgr = image.img
    img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
    Z_hsv = img_hsv.reshape((-1,3))
    Z_hsv = np.float32(Z_hsv)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    ret,label,centers=cv2.kmeans(Z_hsv,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
    centers = np.uint8(centers)
    res_hsv = centers[label.flatten()]
    res_hsv2 = res_hsv.reshape(img_hsv.shape)
    res_bgr = cv2.cvtColor(res_hsv2, cv2.COLOR_HSV2BGR)
    centers_sorted = centers[centers[:, 2].argsort()]
    kmeans_thresholds = []
    for ind in range(K):
        kmeans_thresholds.append(cv2.inRange(res_hsv2,centers_sorted[ind],centers_sorted[ind]))
    summed_image = np.zeros(kmeans_thresholds[0].shape)
    for ind in range(K):
        summed_image += int(ind/K*255) * kmeans_thresholds[ind]
    fig, axs = plt.subplots(2, 2, figsize=(12,6))
    im0=axs.flat[0].imshow(img_bgr)
    im1=axs.flat[1].imshow(res_bgr)
    im2=axs.flat[2].imshow(summed_image, cmap="gray")
    im3=axs.flat[3].imshow(summed_image, cmap="terrain")
    plt.colorbar(im3,ax=axs.flat[3], shrink=0.8)
    save_directory = f"{directory_path}".replace("src", "data")
    # plt.savefig(f"{save_directory}\\kmeans_clustering_applied\\K-{K}\\clustered_view\\{image_sample.split('.PNG')[0]}.png",
    #             format='png')
    plt.savefig(f"{save_directory}\\kmeans_clustering_applied\\ergonautus-10k\\clustered_view\\{image_sample.split('.PNG')[0]}.png",
                format='png')

    ## Per Cluster Masking
    row_ct = int(np.sqrt(K))
    col_ct = int(np.ceil(K/row_ct))
    fig, axs = plt.subplots(row_ct, col_ct, figsize=(12,6), sharex=True, sharey=True)
    for ind in range(row_ct*col_ct):
        if ind < K:
            #target1 = cv2.bitwise_and(image.img,image.img, mask=~kmeans_thresholds[ind])
            target1 = image.img.copy()
            target1[kmeans_thresholds[ind].astype(bool)] = [127,255,127,255]
            axs.flat[ind].imshow(target1)
            spatial_metrics = get_spatial_metrics(kmeans_thresholds[ind])
            hsv_rank = centers_indices[ind]
            hsv_center = centers_sorted[ind]
            # Draw left title
            axs.flat[ind].set_title(
                "HSV \n"+
                f"#{hsv_rank[0]+1}, #{hsv_rank[1]+1}, #{hsv_rank[2]+1}" + "\n" +
                f"({hsv_center[0]}, {hsv_center[1]}, {hsv_center[2]})",
                fontsize=8, loc="left"
            )
            # Draw right title
            axs.flat[ind].set_title(
                f"Location:" + "\n"+
                f"({spatial_metrics['x']['mean']*100:.1f}, {spatial_metrics['y']['mean']:.1%})" + "\n" +
                f"({spatial_metrics['x']['sd']*100:.1f}, {spatial_metrics['y']['sd']:.1%})",
                fontsize=8, loc="right", fontfamily="monospace",
            )
            # axs.flat[ind].set_title(
            #     f"HSV center: [{centers_sorted[ind,0]},{centers_sorted[ind,1]},{centers_sorted[ind,2]}]" )
            #axs.flat[ind].imshow(kmeans_thresholds[ind], cmap="gray")
        else:
            # remove axes for empty cells
            axs.flat[ind].axis("off")
    plt.savefig(f"{save_directory}\\kmeans_clustering_applied\\ergonautus-10k\\per_cluster_mask\\{image_sample.split('.PNG')[0]}.png", format='png')

    # row_ct = int(np.sqrt(K))
    # col_ct = int(np.ceil(K/row_ct))
    # fig, axs = plt.subplots(row_ct, col_ct, figsize=(12,6), sharex=True, sharey=True)
    # for ind in range(row_ct*col_ct):
    #     if ind < K:
    #         target1 = cv2.bitwise_and(image.img,image.img, mask=~kmeans_thresholds[ind])
    #         axs.flat[ind].imshow(target1)
    #         axs.flat[ind].set_title(
    #         f"Mean: {round(snd.mean(target1), 3)}\nStd: {round(snd.standard_deviation(target1), 3)}"
    #     )
    #         # axs.flat[ind].set_title(
    #         #     f"HSV center: [{centers_sorted[ind,0]},{centers_sorted[ind,1]},{centers_sorted[ind,2]}]" )
    #         #axs.flat[ind].imshow(kmeans_thresholds[ind], cmap="gray")
    #     else:
    #         # remove axes for empty cells
    #         axs.flat[ind].axis("off")
    # # plt.savefig(f"{save_directory}\\kmeans_clustering_applied\\K-{K}\\per_cluster_mask\\{image_sample.split('.jpg')[0]}.png", format='png')
    # plt.savefig(f"{save_directory}\\kmeans_clustering_applied\\ergonautus-10k\\per_cluster_mask\\{image_sample.split('.PNG')[0]}.png", format='png')

    # close to prevent overconsumption of memory
    plt.close()
c:\users\ethan\pycharmprojects\eyetraumaanalysis\venv\lib\site-packages\ipykernel_launcher.py:44: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
c:\users\ethan\pycharmprojects\eyetraumaanalysis\venv\lib\site-packages\ipykernel_launcher.py:29: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).